package com.tuanzi.loan.workflow.service.impl;

import java.util.List;
import java.util.Map;

import javax.script.*;

import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.tuanzi.loan.core.exception.SystemException;
import com.tuanzi.loan.workflow.entity.ScriptTask;
import com.tuanzi.loan.workflow.entity.ScriptTaskType;
import com.tuanzi.loan.workflow.repository.ScriptTaskRepository;
import com.tuanzi.loan.workflow.service.ScriptTaskService;

import lombok.extern.slf4j.Slf4j;

/**
 * @author Ray
 * @date 2018/01/16
 */
@Slf4j
@Service
@Transactional
public class ScriptTaskServiceImpl implements ScriptTaskService {

	private static final String DEFAULT_SCRIPT_LANGAUGE = "groovy";

	@Autowired
	private ScriptTaskRepository scriptTaskRepository;

	@Override
	public Object runScript(ScriptTask scriptTask, Map<String, Object> parameters) {
		try {
			return doRunScript(scriptTask.getContent(), parameters);
		} catch (Exception e) {
			log.error("运行脚本失败, procDefId : {} , activityId : {} , scriptTaskType : {}", scriptTask.getProcDefId(), scriptTask.getActivityId(), scriptTask.getTaskType());
			throw new SystemException(e.getMessage(), e);
		}
	}

	@Override
	public Object runScript(ScriptTask scriptTask, Map<String, Object> parameters, String scriptLanguage) {
		try {
			return doRunScript(scriptTask.getContent(), parameters, scriptLanguage);
		} catch (Exception e) {
			log.error("运行脚本失败, procDefId : {} , activityId : {} , scriptTaskType : {}", scriptTask.getProcDefId(), scriptTask.getActivityId(), scriptTask.getTaskType());
			throw new SystemException(e.getMessage(), e);
		}
	}

	@Override
	public Boolean checkGroovyScript(String scriptContent) {
		ScriptEngine engine = getScriptEngine(DEFAULT_SCRIPT_LANGAUGE);
		Compilable compilable = (Compilable) engine;

		try {
			compilable.compile(scriptContent);
			return true;
		} catch (Exception e) {
			log.error("脚本编译错误 : {} ", scriptContent);
			return false;
		}
	}

	private Object doRunScript(String content, Map<String, Object> parameters) throws ScriptException {
		return doRunScript(content, parameters, DEFAULT_SCRIPT_LANGAUGE);
	}

	private Object doRunScript(String content, Map<String, Object> parameters, String scriptLanguage) throws ScriptException {
		ScriptEngine engine = getScriptEngine(scriptLanguage);

		// 设置上下文运行变量
		Bindings binging = engine.createBindings();

		if (MapUtils.isNotEmpty(parameters)) {
			binging.putAll(parameters);
		}

		log.debug("------------------脚本内容输出-开始-------------------");
		log.debug(content);
		log.debug("------------------脚本内容输出-结束-------------------");

		return engine.eval(content, binging);
	}

	private ScriptEngine getScriptEngine(String scriptLanguage) {
		ScriptEngineManager manager = new ScriptEngineManager();
		return manager.getEngineByName(scriptLanguage);
	}

	//
	// @Override
	// public BaseResponse<ScriptTaskResponse>
	// getScriptTaskVO(ScriptTaskQueryRequest request) {
	//
	// BaseResponse<ScriptTaskResponse> response = new
	// BaseResponse<>(ErrorResponseEnum.INVOKE_SUCCESS);
	//
	// ScriptTask record = new ScriptTask();
	// record.setProcDefId(request.getProcDefId());
	// record.setActivityId(request.getActivityId());
	// record.setTaskType(request.getTaskType());
	//
	// ScriptTask scriptTask = mapper.selectOne(record);
	// ScriptTaskResponse scriptTaskResponse = new ScriptTaskResponse();
	// if (null != scriptTask) {
	// ConversionUtil.objectToObject(scriptTask, scriptTaskResponse);
	// try {
	// scriptTaskResponse.setContext(new String(scriptTask.getContext(), "UTF-8"));
	// } catch (UnsupportedEncodingException e) {
	// logger.error("获取脚本内容异常", e);
	// }
	// response.setResult(new BaseResult<>(scriptTaskResponse));
	// } else {
	// scriptTaskResponse.setContext("");
	// response.setResult(new BaseResult<>(scriptTaskResponse));
	// }
	//
	// return response;
	// }
	//
	// @Override
	// public BaseResponse<String> deleteAndsaveScriptTask(ScriptTaskSaveRequest
	// request) {
	//
	// BaseResponse<String> response = new
	// BaseResponse<>(ErrorResponseEnum.INVOKE_SUCCESS);
	//
	// ScriptTaskDeleteRequest deleteRequest = new ScriptTaskDeleteRequest();
	// deleteRequest.setProcDefId(request.getProcDefId());
	// deleteRequest.setTaskType(request.getTaskType());
	// deleteRequest.setActivityId(request.getActivityId());
	//
	// BaseResponse<String> deleteResponse = this.deleteOldData(deleteRequest);
	//
	// if (deleteResponse.getResult().isSuccess()) {
	// ScriptTask record = new ScriptTask();
	// ConversionUtil.objectToObject(request, record);
	// if (null == record.getContext()) {
	// try {
	// record.setContext("".getBytes("UTF-8"));
	// } catch (UnsupportedEncodingException e) {
	// logger.error("保存脚本异常", e);
	// }
	// }
	// int count = mapper.insert(record);
	// if (count == 1) {
	// response.setResult(new BaseResult<>(true, "保存脚本成功"));
	// } else {
	// throw new ServiceException(ErrorResponseEnum.SYSTEM_ERROR.getCode(),
	// "保存脚本失败");
	// }
	// } else {
	// throw new ServiceException(ErrorResponseEnum.SYSTEM_ERROR.getCode(),
	// "保存脚本失败");
	// }
	//
	// return response;
	// }
	//
	// @Override
	// public BaseResponse<String> saveScriptTask(ScriptTaskSaveRequest request) {
	//
	// BaseResponse<String> response = new
	// BaseResponse<>(ErrorResponseEnum.INVOKE_SUCCESS);
	//
	// ScriptTask record = new ScriptTask();
	// ConversionUtil.objectToObject(request, record);
	//
	// ScriptTask scriptTask = mapper.selectOne(record);
	// if (null != scriptTask) {
	// record = scriptTask;
	// }
	//
	// try {
	// if (StringUtils.isNotEmpty(request.getContext())) {
	// record.setContext(request.getContext().getBytes("UTF-8"));
	// } else {
	// record.setContext("".getBytes("UTF-8"));
	// }
	// } catch (UnsupportedEncodingException e) {
	// logger.error("保存脚本内容异常", e);
	// }
	// int count;
	//
	// if (null != record.getId()) {
	// count = mapper.updateByPrimaryKeySelective(record);
	// } else {
	// count = mapper.insert(record);
	// }
	//
	// if (count == 1) {
	// response.setResult(new BaseResult<>(true, "保存脚本成功"));
	// } else {
	// response.setResult(new BaseResult<>(true, "保存脚本失败"));
	// }
	//
	// return response;
	// }
	//
	// @Override
	// public BaseResponse<String> deleteOldData(ScriptTaskDeleteRequest request) {
	//
	// BaseResponse<String> response = new
	// BaseResponse<>(ErrorResponseEnum.INVOKE_SUCCESS);
	//
	// ScriptTask record = new ScriptTask();
	// record.setProcDefId(request.getProcDefId());
	// record.setActivityId(request.getActivityId());
	// record.setTaskType(request.getTaskType());
	//
	// int deleteCount = mapper.delete(record);
	//
	// if (deleteCount == 1) {
	// response.setResult(new BaseResult<>(true, ResponseScript.DEL_SUCCESS));
	// } else {
	// response.setResult(new BaseResult<>(true, ResponseScript.DEL_FAIL));
	// }
	//
	// return response;
	// }
	//
	@Override
	public List<ScriptTask> findAllByProcDefId(String procDefId) {
		return scriptTaskRepository.findAllByProcDefId(procDefId);
	}

	@Override
	public void synchronizeScriptTask(String oldProcDefId, String newProcDefId) {

		List<ScriptTask> oldScriptTasks = findAllByProcDefId(oldProcDefId);

		for (ScriptTask oldScriptTask : oldScriptTasks) {

			ScriptTask newScriptTask = new ScriptTask();
			BeanUtils.copyProperties(oldScriptTask, newScriptTask, new String[] { "id" });
			newScriptTask.setProcDefId(newProcDefId);
			scriptTaskRepository.save(newScriptTask);

		}
	}

	@Override
	public void deleteByProcDefId(String procDefId) {
		scriptTaskRepository.deleteInBatch(scriptTaskRepository.findAllByProcDefId(procDefId));
	}

	@Override
	public List<ScriptTask> findAllByProcDefIdAndActivityId(String procDefId, String activityId) {
		return scriptTaskRepository.findAllByProcDefIdAndActivityId(procDefId, activityId);
	}

	@Override
	public ScriptTask findByProcDefIdAndActivityIdAndTaskType(String procDefId, String activityId, ScriptTaskType TaskType) {
		return scriptTaskRepository.findByProcDefIdAndActivityIdAndTaskType(procDefId, activityId, TaskType);
	}

	@Override
	public ScriptTask saveOrUpdate(ScriptTask scriptTask) {
		return scriptTaskRepository.save(scriptTask);
	}

	@Override
	public void delete(ScriptTask scriptTask) {
		scriptTaskRepository.delete(scriptTask);
	}
}
